package cn.com.dhcc.ddi.task.service.extract.impl;

import cn.com.dhcc.app.core.exception.DaoException;
import cn.com.dhcc.app.core.service.Log;
import cn.com.dhcc.app.core.tag.CommonStaticCode;
import cn.com.dhcc.app.core.util.JsonUtil;
import cn.com.dhcc.app.core.util.UUIDGenerator;
import cn.com.dhcc.app.core.util.XstreamUtil;
import cn.com.dhcc.app.pub.core.consts.AppIocBean;
import cn.com.dhcc.app.pub.core.consts.DdiProperties;
import cn.com.dhcc.app.pub.core.tag.staticcode.StaticCode;
import cn.com.dhcc.app.pub.core.util.filefilter.DirFilter;
import cn.com.dhcc.app.pub.core.util.filefilter.RegexFilter;
import cn.com.dhcc.ddi.datamapping.dao.DataMappingDao;
import cn.com.dhcc.ddi.datamapping.vo.DataMapping;
import cn.com.dhcc.ddi.datasource.dao.DataSourceDao;
import cn.com.dhcc.ddi.datasource.vo.DataSourceConfVo;
import cn.com.dhcc.ddi.datasource.vo.DataSourceVo;
import cn.com.dhcc.ddi.task.dao.TaskExecuteLogDao;
import cn.com.dhcc.ddi.task.dao.TaskFilterDao;
import cn.com.dhcc.ddi.task.service.DataSet;
import cn.com.dhcc.ddi.task.service.Result;
import cn.com.dhcc.ddi.task.service.extract.EDataSourceInterface;
import cn.com.dhcc.ddi.task.service.transform.MapOrder;
import cn.com.dhcc.ddi.task.vo.Task;
import cn.com.dhcc.ddi.task.vo.TaskExecuteLog;
import cn.com.dhcc.ddi.task.vo.TaskFilter;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.channels.FileChannel;
import java.util.*;

@Service(AppIocBean.E_DATASOURCE_LOCALDISK_IMPL)
public class EDataSourceLocalDiskImpl implements EDataSourceInterface {
    private static Logger logger = Log.getLogger(Log.LOGTYPE.DDI);
    @Autowired
    private TaskFilterDao taskFilterDao;
    @Autowired
    private TaskExecuteLogDao taskExecuteLogDao;
    @Autowired
    private DataMappingDao dmDao;
    @Autowired
    private DataSourceDao dsDao;

    @Override
    public Result extractData(Task task, String taskLogId) throws DaoException {
        Result result = new Result();
        result.setTaskLogId(taskLogId);
        String resultMsg = "";
        //服务器任务数据文件抽取目录
        String extractPath = DdiProperties.APP_UPLOAD_FILEDATA_PATH + File.separator + TaskExecuteLog.LINK_TYPE.EXTRACT.getEname() + File.separator + task.getId() + File.separator + taskLogId;
        File extractFolder = new File(extractPath);
        if (!extractFolder.exists()) {
            extractFolder.mkdirs();
        }
        List<String> failFileList = sendFailTask(task,taskLogId);
        boolean taskExecuteSuccess = true;
        TaskExecuteLog extractLog = new TaskExecuteLog();
        extractLog.setId(UUIDGenerator.getUUID());
        extractLog.setTaskId(task.getId());
        extractLog.setLinkType(TaskExecuteLog.LINK_TYPE.EXTRACT.getCode());
        extractLog.setLinkStartTime(new Date());
        extractLog.setMtime(new Date());
        extractLog.setGroupId(taskLogId);
        result.setLinkLogId(extractLog.getId());
        result.setTaskLogId(extractLog.getGroupId());

        //文件名称
        List<String> fileNameList = new ArrayList<String>();
        //文件服务器存储路径
        List<String> fileDirList = new ArrayList<String>();
        //文件相对路径
        List<String> fileRelativePath = new ArrayList<String>();
        taskExecuteLogDao.insert(extractLog);

        TaskFilter filter = taskFilterDao.getTaskFilterByTaskId(task.getId());
        DataMapping dm = dmDao.get(task.getMpId());
        DataSourceVo ds = dsDao.get(dm.getSrcDsId());

        boolean sendChlidDirflag = false;
        if (CommonStaticCode.YESNO.YES.getStatus().equals(filter.getChlidDir())) {
            sendChlidDirflag = true;
        }
        DataSourceConfVo dsConfVo = JsonUtil.toObject(ds.getConf(), DataSourceConfVo.class);
        File extractDir = new File(dsConfVo.getDiskDirectory());


        List<File> names = new ArrayList<File>();
        FileChannel fc = null;
        if (StaticCode.FilterTypeEnum.WILDCARD.getCode().equals(filter.getFilterType())) {
            DirFilter df = new DirFilter(filter.getFilterValue());
            method(extractDir.listFiles(df), names, df,
                    filter.getFilterValue(), sendChlidDirflag);
        } else {
            RegexFilter rf = new RegexFilter(filter.getFilterValue());
            method(extractDir.listFiles(rf), names, rf, "*.*", sendChlidDirflag);
        }


        long fileSize = 0;
        try {
            for (int i = 0; i < names.size(); i++) {
                File f = names.get(i);
                if (f.exists() && f.isFile()) {
                    FileInputStream fis = new FileInputStream(f);
                    fc = fis.getChannel();
                    if (fc.size() >= filter.getSizeMin() * 1024) {
                        String absolutePath = "";
                        String relativePath = f.getAbsolutePath().substring(extractDir.getAbsolutePath().length() + 1);
                        boolean flag = false;
                        if (filter.getSizeMax() != null && filter.getSizeMax() > 0) {
                            if (fc.size() <= filter.getSizeMax() * 1024) {
                                flag = true;
                            } else {
                                continue;
                            }
                        } else {
                            flag = true;
                        }
                        if (flag) {
                            File temp = new File(extractFolder + File.separator + relativePath);
                            FileUtils.copyFile(f, temp);
                            absolutePath = temp.getAbsolutePath();
                            fis.close();
                            fc.close();
                            f.getAbsoluteFile().delete();
                            fileNameList.add(names.get(i).getName());
                            fileDirList.add(absolutePath);
                            fileRelativePath.add(relativePath);
                            fileSize += temp.length();
                        }
                    }
                }
            }
            fileRelativePath.addAll(failFileList);
            taskExecuteSuccess = true;
        } catch (IOException e) {
            logger.error("数据抽取失败", e);
            taskExecuteSuccess = false;
        }
        extractLog.setLinkEndTime(new Date());
        if (taskExecuteSuccess) {
            String contentDetail = createSendContentDetail(fileNameList);
            extractLog.setLinkSummary(contentDetail);
            //保存文件相对路径
            extractLog.setLinkDataFilePath(JsonUtil.toJson(fileRelativePath));
            extractLog.setTotal(fileNameList.size());
            extractLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
            result.setStatus(CommonStaticCode.SUCCESSFAIL.SUCCESS.getStatus());
            result.setMsg("数据抽取成功");
        } else {
            String failRoot = DdiProperties.APP_UPLOAD_FILEDATA_PATH + File.separator + "fail" + File.separator + task.getId() + File.separator + taskLogId;
            try {
                for (String relativePath:fileRelativePath) {
                    File file = new File(extractFolder + File.separator + relativePath);
                    File temp = new File(failRoot + File.separator + relativePath);
                    FileUtils.copyFile(file, temp);
                    file.delete();
                }
            } catch (IOException e) {
                logger.error(e);
            }
            extractLog.setLogMsg("数据抽取失败");
            extractLog.setLogStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
            result.setStatus(CommonStaticCode.SUCCESSFAIL.FAIL.getStatus());
            result.setMsg("数据抽取失败");

        }
        taskExecuteLogDao.update(extractLog);
        return result;
    }

    @Override
    public DataSet extractData(String dataSourceMeteData,
                               Set<MapOrder> mapOrders) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Result loadData(String dataSourceMeteData, DataSet dataSets) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void reciveNotify(String taskLogId, String status, String msg) {

    }

    /**
     * 文件名匹配
     *
     * @param files 被匹配文件列表
     * @param list 匹配成功文件列表
     * @param filefilter  文件过滤器
     * @param type 过滤条件
     * @param flag 是否包含子目录
     */
    public static void method(File[] files, List<File> list,
                              FilenameFilter filefilter, String type, boolean flag) {
        if (files != null) {
            if (flag) {
                for (File f : files) {
                    if (f.isDirectory())
                        method(f.listFiles(filefilter), list, filefilter, type,
                                flag);
                    else if (DirFilter.match(type, f.getName())) {
                        list.add(f);
                    }
                }
            } else {
                for (File f : files) {
                    if (DirFilter.match(type, f.getName())) {
                        list.add(f);
                    }
                }
            }
        }
    }
    public List<String> sendFailTask(Task task ,String extractDir) {
        List<String> failFileList = new ArrayList<String>();
        try {
            String failRoot = DdiProperties.APP_UPLOAD_FILEDATA_PATH + File.separator + "fail" + File.separator + task.getId();
            String linkType = TaskExecuteLog.LINK_TYPE.EXTRACT.getCode();
            List<TaskExecuteLog> failLogs = taskExecuteLogDao.getFailTaskLog(task.getId());// 失败任务日志
            if (failLogs.size() == 0) {
                return failFileList;
            }
            for (Iterator<TaskExecuteLog> iterator = failLogs.iterator(); iterator
                    .hasNext();) {
                TaskExecuteLog failLog = iterator.next();
                    File dir = new File(failRoot+File.separator +failLog.getId());
                    List<File> names = new ArrayList<File>();
                    List<String> fileNames = new ArrayList<String>();
                    DirFilter df = new DirFilter("*.*");
                    method(dir.listFiles(df), names, df, "*.*", true);
                    List<String> fileItems = new ArrayList<String>();
                    if (names.size() == 0) {
                        continue;
                    }
                    for (int i = 0; i < names.size(); i++) {
                        File f = names.get(i);
                        if (f.exists() && f.isFile()) {
                            String absolutePath = f.getAbsolutePath();
                            String relativePath = absolutePath.substring(dir.getAbsolutePath().length() + 1);
                            File temp = new File(extractDir + File.separator + relativePath);
                            FileUtils.copyFile(f, temp);
                            failFileList.add(relativePath);
                            f.delete();
                        }
                    }
            }
        } catch (Exception e) {
            logger.error(e);
        }
        return failFileList;
    }
    private String createSendContentDetail(List<String> fileNames) {
        StringBuffer rs = new StringBuffer();
        StringBuilder files = new StringBuilder();
        if (fileNames.size() == 0) {
           return  "本次任务没有交换的数据文件。";
        }
        for (String fileName:fileNames){
            files.append("文件：").append(fileName).append("\r\n");
        }
        rs.append("数据抽取结果,总数：" + fileNames.size()).append("\r\n").append(files.toString()).append("\r\n");
        return rs.toString();
    }
}
